package com.zyg.mydatasource;

import com.zyg.myconnection.MyConnection02;
import com.zyg.myconnection.MyConnection03;
import com.zyg.utils.JDBCUtil;

import javax.sql.DataSource;
import java.io.PrintWriter;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;

/**
 * 自定义数据库连接池
 */
public class MyDataSource implements DataSource {
    //1.准备一个容器。用于保存多个数据库连接对象（保证线程安全）
    private static List<Connection> pool = Collections.synchronizedList(new ArrayList<>());

    //2.定义静态代码块,获取多个连接对象保存到容器中
    static{
        for(int i = 1; i <= 10; i++) {
            Connection con = JDBCUtil.getConnection();
            pool.add(con);
        }
    }

    //3.提供一个获取连接池大小的方法
    public int getSize() {
        return pool.size();
    }


    //4.重写getConnection方法，用于返回一个连接对象

//    /**
//     * 4.1 直接关闭连接
//     * @return
//     * @throws SQLException
//     */
//    @Override
//    public Connection getConnection() throws SQLException {
//        if (pool.size()>0){
//            return pool.remove(0);
//        }else {
//            throw new RuntimeException("连接池数量已用尽");
//        }
//    }

//    /**
//     * 4.2 装饰者模式包装连接对象
//     * 此种方式存在的问题：大量非核心功能需要重写
//     * @return
//     * @throws SQLException
//     */
//    @Override
//    public Connection getConnection() throws SQLException {
//        if (pool.size()>0){
//            Connection connection = pool.remove(0);
//            MyConnection02 myConnection02 = new MyConnection02(connection, pool);
//            return myConnection02;
//        }else {
//            throw new RuntimeException("连接池数量已用尽");
//        }
//    }

//    /**
//     * 4.3 适配器模式包装连接对象
//     * 此种方式虽屏蔽了非核心方法的重写，较为简洁，但转移到适配器中间类去了(适配器类需自己编写)
//     * @return
//     * @throws SQLException
//     */
//    @Override
//    public Connection getConnection() throws SQLException {
//        if (pool.size()>0){
//            Connection connection = pool.remove(0);
//            MyConnection03 myConnection03 = new MyConnection03(connection, pool);
//            return myConnection03;
//        }else {
//            throw new RuntimeException("连接池数量已用尽");
//        }
//    }

    /**
     * 4.4 动态代理方式归还连接
     * @return
     * @throws SQLException
     */
    @Override
    public Connection getConnection() throws SQLException {
        if (pool.size()>0){
            Connection connection = pool.remove(0);
            Connection connectionProxy = (Connection) Proxy.newProxyInstance(connection.getClass().getClassLoader(), new Class[]{Connection.class}, new InvocationHandler() {
                /*
                    执行Connection实现类连接对象所有的方法都会经过invoke
                    如果是close方法，归还连接
                    如果不是，直接执行连接对象原有的功能即可
                 */
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    if ("close".equals(method.getName())){
                        //归还连接
                        pool.add(connection);
                        return null;
                    }else {
                        return method.invoke(connection,args);
                    }
                }
            });
            return connectionProxy;
        }else {
            throw new RuntimeException("连接池数量已用尽");
        }
    }
    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        return null;
    }

    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        return null;
    }

    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return false;
    }

    @Override
    public PrintWriter getLogWriter() throws SQLException {
        return null;
    }

    @Override
    public void setLogWriter(PrintWriter out) throws SQLException {

    }

    @Override
    public void setLoginTimeout(int seconds) throws SQLException {

    }

    @Override
    public int getLoginTimeout() throws SQLException {
        return 0;
    }

    @Override
    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
        return null;
    }
}
